/****************************************
*  This file created using "Writer B"   *
*      a program written by CTonk       *
*          ctonk87@hotmail.com          *
*     [timestamp 02/20/06  12:51:45]    *
****************************************/

// Area.cpp

#ifndef CPP_AREA
#define CPP_AREA

#include "definitions.h"
#include "area.h"
#include "stringutil.h"
#include "timestamp.h"
#include "mob.h"
#include "object.h"
#include "world.h"
#include "reset.h"

int Area::numAreas = 0;

// Constructors...
Area::Area() {
	_number = numAreas;
	numAreas++;
	_firstv = 0;
	_lastv = 0;
	_size = 0;
	_keyword = new char[20];
	for ( int x=0; x < 20; x++ )
		_keyword[x] = '\0';
	_file = new char[55];
	for ( int x=0; x < 55; x++ )
		_file[x] = '\0';
	_name = new char[40];
	for ( int x=0; x < 40; x++ )
		_name[x] = '\0';
	// Set up area and initial reset times.
	time_t current;
	time( &current );
	_nextReset = (time_t)( rand() % UPPER_RESET + LOWER_RESET );
}

Area::Area( Area& it ) {
	_number = it._number;
	_firstv = it._firstv;
	_lastv = it._lastv;
	_size = it._size;
	for ( int x=0; x < 20; x++ )
		_keyword[x] = it._keyword[x];
	for ( int x=0; x < 55; x++ )
		_file[x] = it._file[x];
	for ( int x=0; x < 40; x++ )
		_name[x] = it._name[x];
	_rooms = it.getRooms();
	_nextReset = it._nextReset;
	numAreas++;
}

Area::~Area() {
	delete[] _keyword;
	delete[] _file;
	delete[] _name;
	numAreas--;
}

// Operators...
Area& Area::operator = ( Area& it ) {
	_number = it._number;
	_firstv = it._firstv;
	_lastv = it._lastv;
	_size = it._size;
	for ( int x=0; x < 20; x++ )
		_keyword[x] = it._keyword[x];
	for ( int x=0; x < 55; x++ )
		_file[x] = it._file[x];
	for ( int x=0; x < 40; x++ )
		_name[x] = it._name[x];
	_rooms = it.getRooms();
	_nextReset = it._nextReset;
	return *this;
}

/*Room* Area::operator [] ( int number ) {
	return this->_rooms[ number ];
}*/

// Public accessor methods...
int Area::GetNumber()
{
	return _number;
}

void Area::SetNumber( int number )
{
	_number = number;
}

int Area::GetFirstv()
{
	return _firstv;
}

void Area::SetFirstv( int firstv )
{
	_firstv = firstv;
}

int Area::GetLastv()
{
	return _lastv;
}

void Area::SetLastv( int lastv )
{
	_lastv = lastv;
}

int Area::GetSize()
{
	return _size;
}

void Area::SetSize( int size )
{
	_size = size;
}

char* Area::GetKeyword( void )
{
	return _keyword;
}

char Area::GetKeyword( int x )
{
	return _keyword[x];
}

void Area::SetKeyword( char* val )
{
	strcpy( _keyword, val );
	return;
}

void Area::SetKeyword( const char* val )
{
	strcpy( _keyword, val );
	return;
}

void Area::SetKeyword( int x, char val )
{
	_keyword[x] = val;
}

char* Area::GetFile( void )
{
	return _file;
}

char Area::GetFile( int x )
{
	return _file[x];
}

void Area::SetFile( char* val )
{
	strcpy( _file, val );
	return;
}

void Area::SetFile( const char* val )
{
	strcpy( _file, val );
	return;
}

void Area::SetFile( int x, char val )
{
	_file[x] = val;
}

char* Area::GetName( void ) {
	return _name;
}

char Area::GetName( int x )
{
	return _name[x];
}

void Area::SetName( char* val )
{
	strcpy( _name, val );
	return;
}

void Area::SetName( const char* val )
{
	strcpy( _name, val );
	return;
}

void Area::SetName( int x, char val )
{
	_name[x] = val;
}

void Area::setNextReset( time_t nextReset ) {
	_nextReset = nextReset;
	return;
}

time_t Area::getNextReset() {
	return _nextReset;
}

std::list< int >& Area::getPermissions() {
	return _permissions;
}

void Area::addPermission( int perm ) {
	std::list< int >::iterator it;

	for ( it = _permissions.begin(); it != _permissions.end(); it++ )
		if ( (*it) == perm )
			return;

	_permissions.push_back( perm );

	return;
}

bool Area::getPermission( int perm ) {
	std::list< int >::iterator it;

	if ( _number == 0 )
		return false;

	for ( std::list< Character* >::iterator c = World::Instance().getClist().begin(); c != World::Instance().getClist().end(); c++ )
		if ( (*c)->getLevel() >= HEAD )
			return true;

	for ( it = _permissions.begin(); it != _permissions.end(); it++ )
		if ( (*it) == perm )
			return true;

	return false;
}

void Area::dropPermission( int perm ) {
	_permissions.remove( perm );
	return;
}

std::list< Room* >& Area::getRooms() {
	return _rooms;
}

Room* Area::addRoom() {
	Room* room = new Room;
	_rooms.push_back( room );
	room->setArea( this );
	return room;
}

Room* Area::getRoom( int room ) {
	std::list< Room* >::iterator it;

	for ( it = _rooms.begin(); it != _rooms.end(); it++ )
		if ( (*it)->GetVnum() == room )
			return *it;

	// Mob not found...
	return NULL;
}

std::list< Mob* >& Area::getMobs() {
	return _mobs;
}

Mob* Area::addMob() {
	Mob* mob = 0;
	_mobs.push_back( ( mob = new Mob ) );
	mob->setArea( this );
	return mob;
}

Mob* Area::getMob( int mob ) {
	std::list< Mob* >::iterator it;

	for ( it = _mobs.begin(); it != _mobs.end(); it++ )
		if ( (*it)->getVnum() == mob )
			return *it;

	// Mob not found...
	return NULL;
}

std::list< Object* >& Area::getObjects() {
	return _objects;
}

Object* Area::addObject() {
	Object* obj = 0;
	//_objects.push_back( ( obj = new Object ) );
	//obj->setArea( this ); // is this needed?
	return obj;
}

Object* Area::getObject( int obj ) {
	int i = 0;
	for ( std::list< Object* >::iterator it = _objects.begin(); it != _objects.end(); it++, i++ )
		if ( i == obj )
			return (*it);

	// Object not found...
	return NULL;
}

std::list< Reset* >& Area::getResets() {
	return _resets;
}

// Other methods...
Object* Area::createObject( int vnum, int room_vnum, int number, int limit ) {
	Object* obj = 0;
	Room* room = 0;
	Area* area = 0;
	std::list< Object* >::iterator it;

	if ( ( room = World::Instance().FindRoom( room_vnum ) ) == NULL )
		return NULL;
	area = room->getArea();

	for ( it = area->getObjects().begin(); it != area->getObjects().end(); it++ )
		if ( (*it)->getVnum() == vnum ) {
			switch ( (*it)->getType() ) {
				case ACCESSORY:
					obj = new Accessory; break;
				case ARMOR:
					obj = new Armor; break;
				case BODY_PART:
					obj = new Body_Part; break;
				case CLOTHING:
					obj = new Clothing; break;
				case COIN:
					obj = new Coin; break;
				case CONTAINER:
					obj = new Container; break;
				case DRINK:
					obj = new Drink; break;
				case FOOD:
					obj = new Food; break;
				case FURNITURE:
					obj = new Furniture; break;
				case JEWELRY:
					obj = new Jewelry; break;
				case SCROLL:
					obj = new Scroll; break;
				case TRASH:
					obj = new Trash; break;
				case WAND:
					obj = new Wand; break;
				case WEAPON:
					obj = new Weapon; break;
				default: // something funky happened
					return NULL; break;
			}
			obj->copy( *it );
		}

	if ( obj == NULL ) // object doesn't exist
		return NULL;

	// Object was found and created successfully, let's integrate it.
	room->getOlist().push_back( obj );
	World::Instance().getOlist().push_back( obj );

	return obj;
}

void Area::resetArea() {
	time_t current;
	time( &current );
	Reset* reset = 0;

	for ( std::list< Reset* >::iterator it = _resets.begin(); it != _resets.end(); it++ ) {
		reset = *it;
		////////////////////////////////// Mob
		if ( reset->getType() == MOB ) {
			Mob* target = 0;
			Mob* mob = 0;
			int mobCount = 0;
			int added = 0;
			for ( std::list< Mob* >::iterator it = World::Instance().getMlist().begin(); it != World::Instance().getMlist().end(); it++ )
				if ( (*it)->getArea() == this && (*it)->getVnum() == reset->getTarget() )
					mobCount++;
			for ( std::list< Mob* >::iterator it = _mobs.begin(); it != _mobs.end(); it++ )
				if ( (*it)->getVnum() == reset->getTarget() )
					target = *it;
			if ( target != 0 ) {
				while ( mobCount < reset->getLimit() && added < reset->getNumber() ) {
					mob = new Mob( *target );
					World::Instance().getMlist().push_back( mob );
					World::Instance().FindRoom( reset->getVnum() )->Add( mob );
					mob->setRoom( World::Instance().FindRoom( reset->getVnum() )->GetVnum() );
					mobCount++;
					added++;
				}
			} else
				std::cerr << "Area::resetArea()... Mob " << reset->getTarget() << " didn't load into room " << reset->getVnum() << '\n';
		}
		////////////////////////////////// Object
		if ( reset->getType() == OBJECT ) {
			Object* target = 0;
			int objCount = 0;
			for ( std::list< Object* >::iterator it = World::Instance().getOlist().begin(); it != World::Instance().getOlist().end(); it++ )
				if ( (*it)->getVnum() == reset->getTarget() )
					objCount++;
			for ( std::list< Object* >::iterator it = _objects.begin(); it != _objects.end(); it++ )
				if ( (*it)->getVnum() == reset->getTarget() )
					target = *it;
			if ( target != 0 )
				createObject( target->getVnum(), reset->getVnum(), reset->getNumber(), reset->getLimit() );
			else
				std::cerr << "Area::resetArea()... Object " << reset->getTarget() << " didn't load into room " << reset->getVnum() << '\n';
		}
	}

	// Set the time for the next reset.
	_nextReset = current + (time_t)(rand() % UPPER_RESET + LOWER_RESET );

	return;
}

void Area::loadObject( std::ifstream& read ) {
	char ctemp[2048];
	int	vnum = 0;
	std::string type;
	int flags;
	std::string keywords;
	std::string short_desc;
	std::string long_desc;
	std::string full_desc;
	Object* obj = NULL;

	// Read base object data...
	read >> vnum >> type >> flags;
	read.get();
	read.getline( ctemp, 2048 );
	keywords = ctemp;
	read.getline( ctemp, 2048 );
	short_desc = ctemp;
	read.getline( ctemp, 2048 );
	long_desc = ctemp;
	read.getline( ctemp, 2048, '$' );
	full_desc = ctemp;

	obj = Object::getNewObject( Object::objectType( type ) );

	if ( obj == NULL )
		return;

	obj->setVnum( vnum );
	obj->setType( Object::objectType( type ) );
	obj->setFlags( flags );
	obj->setKeywords( keywords );
	obj->setShort( short_desc );
	obj->setLong( long_desc );
	obj->setDesc( full_desc );

	if ( obj != NULL )
		obj->load( read );
	else
		return;

	getObjects().push_back( obj );

	return;
}

void Area::Save( std::ofstream& save ) {
	save << _firstv << ' ' << _lastv << ' ' << _keyword << '\n';
	save << _name << '\n';
	save << _permissions.size() << ' ';
	for ( std::list< int >::iterator it = _permissions.begin(); it != _permissions.end(); it++ )
		save << (*it) << ' ';
	save << '\n';

	// Save rooms in sequence...
	for ( int i = _firstv; i <= _lastv ; i++ )
		for ( std::list< Room* >::iterator it = _rooms.begin(); it != _rooms.end(); it++ )
			if ( (*it)->GetVnum() == i )
				(*it)->Save( save );

	// Save mobs in sequence...
	for ( int i = _firstv; i <= _lastv; i++ )
		for ( std::list< Mob* >::iterator it = _mobs.begin(); it != _mobs.end(); it++ )
			if ( (*it)->getVnum() == i )
				(*it)->mSave( save );

	// Save objects in sequence...
	for ( int i = _firstv; i <= _lastv; i++ )
		for ( std::list< Object* >::iterator it = _objects.begin(); it != _objects.end(); it++ )
			if ( (*it)->getVnum() == i )
				(*it)->save( save );

	// Save resets in sequence...
	for ( int i = _firstv; i <= _lastv; i++ )
		for ( std::list< Reset* >::iterator it = _resets.begin(); it != _resets.end(); it++ )
			if ( (*it)->getVnum() == i )
				(*it)->Save( save );

	return;
}

void Area::Load( std::ifstream& load ) {
	char* temp = new char[2048];
	int itemp = 0;
	int numberPerms = 0;
	Mob* mob = 0;
	Reset* reset = 0;

	load >> _firstv >> _lastv >> _keyword;
	load.get(); load.getline( _name, 2048 );
	_size = _lastv - _firstv + 1;
	load >> numberPerms;
	for ( int i=0; i < numberPerms; i++ ) {
		load >> itemp;
		addPermission( itemp );
	}

	while ( load.peek() != EOF ) {
		load.getline( temp, 2048 );
		if ( strcmp( temp, "**ROOM" ) == 0 ) {
			addRoom()->Load( load );
			continue;
		}
		if ( strcmp( temp, "**MOB" ) == 0 ) {
			mob = addMob(); // Add mob to the area list.
			mob->mLoad( load );
			continue;
		}
		if ( strcmp( temp, "**OBJECT" ) == 0 ) {
			loadObject( load );
			continue;
		}
		if ( strcmp( temp, "**RESET" ) == 0 ) {
			_resets.push_back( reset = new Reset );
			reset->Load( load );
			continue;
		}
	}

	return;
}



#endif // #ifndef CPP_AREA
